package com.ruoyi.iot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.alert.service.IIotAlertLogService;
import com.ruoyi.common.influx.InfluxDBConfig;
import com.ruoyi.common.utils.sql.InsertSqlUtil;
import com.ruoyi.iot.domain.IotDataWaterPressureInfo;
import com.ruoyi.iot.domain.IotMeasurementDict;
import com.ruoyi.iot.domain.IotSensor;
import com.ruoyi.iot.domain.IotSensorMsg;
import com.ruoyi.iot.mapper.IotMeasurementDictMapper;
import com.ruoyi.iot.mapper.IotSensorMapper;
import com.ruoyi.iot.mapper.IotSensorMsgMapper;
import com.ruoyi.iot.service.IIotSensorCollectService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class IotSensorCollectServiceImpl implements IIotSensorCollectService {

    private final InfluxDBConfig influxDBConfig;

    private final IotMeasurementDictMapper iotMeasurementDictMapper;

    private final JdbcTemplate jdbcTemplate;

    @Resource
    private IotSensorMapper iotSensorMapper;
    @Resource
    private IotSensorMsgMapper iotSensorMsgMapper;

    @Resource
    private IIotAlertLogService iIotAlertLogService;

    @Override
    public Boolean saveToInfluxDB(String measurement, Map<String, String> tags, Map<String, Object> fields) {
        influxDBConfig.insert(measurement, tags, fields);
        return true;
    }
    @Override
    public  Boolean saveToInfluxDB(Long timestamp, String measurement, Map<String, String> tags, Map<String, Object> fields) {
        System.out.println(measurement + ":"+timestamp);
        influxDBConfig.insert(measurement, timestamp,tags, fields);
        return true;
    };

    @Override
    public List<Map<String, Object>> queryList(Map<String, Object> params) {
        String format = (String) params.getOrDefault("format","yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        String fluxSql = BuildQueryParameter(params);
        System.out.println(fluxSql);
        List<Map<String, Object>> results = influxDBConfig.queryResultProcess(influxDBConfig.query(fluxSql));
        return  results.stream()
            .peek(result -> result.put("time", formatter.format(DateUtil.parseUTC((String) result.get("time")))))
            .collect(Collectors.toList());
    }

    /**
     * 根据参数构建插入或者更新语句
     * @param tableName 表名
     * @param tags 标签映射
     * @param stringObjectMap 字段映射
     * @return 操作是否成功
     */
    @Override
    public Boolean saveToMysql(String tableName, Map<String, String> tags, Map<String, Object> stringObjectMap) {
        // 边界条件检查
        if (tableName == null || tableName.isEmpty()) {
            throw new IllegalArgumentException("Measurement cannot be null or empty");
        }
        if (tags == null || tags.isEmpty() || stringObjectMap == null || stringObjectMap.isEmpty()) {
            throw new IllegalArgumentException("Tags and stringObjectMap cannot be null or empty");
        }
        // 获取 remoteId
        String remoteId = tags.get("remote_id");
        if (remoteId == null || remoteId.isEmpty()) {
            throw new IllegalArgumentException("remoteId cannot be null or empty");
        }

        //TODO
        //特判 水质 的情况 水质只传remoteId即iot_sensor.deviceId
        if (tableName.equals("iot_data_water_quality")){
            List<String> objects = iotMeasurementDictMapper.selectDeviceIdListByRemoteId(tableName, remoteId);
            objects.forEach(deviceId -> {
                Map<String,String> newTags = new HashMap<>();
                BeanUtil.copyProperties( tags, newTags);
                newTags.put("device_id", deviceId);
                iIotAlertLogService.hanlerAlert(tableName, newTags, stringObjectMap);
            });
        } else {
            iIotAlertLogService.hanlerAlert(tableName, tags, stringObjectMap);
        }


        // 获取 deviceId
        String deviceId = tags.get("device_id");
        List<String> objects;
        if (deviceId == null || deviceId.isEmpty()) {
            // 检查是否存在记录
            objects = iotMeasurementDictMapper.selectListByRemoteId(tableName, remoteId);
        }else {
            objects = iotMeasurementDictMapper.selectListByRemoteIdAndDeviceId(tableName, remoteId, deviceId);
        }

        boolean exists = !objects.isEmpty();

        String sql;
        if (exists) {
            // 构建更新SQL语句
            StringBuilder updateSqlBuilder = new StringBuilder("UPDATE ").append(tableName).append(" SET ");
            int paramIndex = 0;
            List<Object> params = new ArrayList<>();
            for (String fieldKey : stringObjectMap.keySet()) {
                updateSqlBuilder.append(fieldKey).append(" = ?, ");
                params.add(stringObjectMap.get(fieldKey));
                paramIndex++;
            }
            // 去掉最后一个 ", "
            updateSqlBuilder.setLength(updateSqlBuilder.length() - 2);
            updateSqlBuilder.append(" WHERE remote_id = ?");
            params.add(remoteId); // 添加 remote_id 参数
            if (deviceId != null && !deviceId.isEmpty()){
                updateSqlBuilder.append(" AND device_id = ?");
                params.add(deviceId);
            }

            sql = updateSqlBuilder.toString();
            try {
                return jdbcTemplate.update(sql, params.toArray()) > 0;
            } catch (Exception e) {
                // 记录日志
                System.err.println("Error executing SQL: " + e.getMessage());
                return false;
            }
        } else {
            // 构建插入SQL语句
            sql = InsertSqlUtil.buildInsertSql(tableName, tags.keySet(), stringObjectMap.keySet());
        }
        try {
            return jdbcTemplate.update(connection -> {
                PreparedStatement pstmt = connection.prepareStatement(sql);
                int index = 1;
                for (String tagValue : tags.values()) {
                    pstmt.setString(index++, tagValue);
                }
                for (Object fieldValue : stringObjectMap.values()) {
                    pstmt.setObject(index++, fieldValue);
                }
                return pstmt;
            }) > 0;
        } catch (Exception e) {
            // 记录日志
            System.err.println("Error executing SQL: " + e.getMessage());
            return false;
        }
    }

    /**
     * 批量插入或更新数据，基于 remote_id 和 device_id 双条件判断
     *
     * @param tableName 表名
     * @param batchData 批量数据，每个元素包含 tags 和 fields
     * @return 操作是否成功
     */
    @Override
    public Boolean batchSaveToMysql(String tableName, List<Map<String, Object>> batchData) {
        // 参数校验
        if (tableName == null || tableName.isEmpty()) {
            throw new IllegalArgumentException("表名不能为空");
        }
        if (batchData == null || batchData.isEmpty()) {
            throw new IllegalArgumentException("批量数据不能为空");
        }

        // 获取 mapper 和 jdbcTemplate
        List<String> existRemoteIds = new ArrayList<>();
        for (Map<String, Object> data : batchData) {
            Map<String, String> tags = (Map<String, String>) data.get("tags");
            Map<String, Object> fields = (Map<String, Object>) data.get("fields");

            String remoteId = tags.get("remote_id");
            String deviceId = tags.get("device_id");

            // 校验 remote_id 和 device_id
            if (remoteId == null || deviceId == null || remoteId.isEmpty() || deviceId.isEmpty()) {
                throw new IllegalArgumentException("remote_id 或 device_id 不能为空");
            }

            //TODO
            iIotAlertLogService.hanlerAlert(tableName, tags, fields);

            // 查询是否存在记录
            boolean exists = !iotMeasurementDictMapper.checkExistByRemoteIdAndDeviceId(tableName, remoteId, deviceId).isEmpty();

            String sql;
            if (exists) {
                // 构建更新SQL语句
                StringBuilder updateSqlBuilder = new StringBuilder("UPDATE ").append(tableName).append(" SET ");
                List<Object> params = new ArrayList<>();

                for (String fieldKey : fields.keySet()) {
                    updateSqlBuilder.append(fieldKey).append(" = ?, ");
                    params.add(fields.get(fieldKey));
                }

                // 去掉最后一个 ", "
                updateSqlBuilder.setLength(updateSqlBuilder.length() - 2);
                updateSqlBuilder.append(" WHERE remote_id = ? AND device_id = ?");
                params.add(remoteId);
                params.add(deviceId);

                sql = updateSqlBuilder.toString();

                try {
                    jdbcTemplate.update(sql, params.toArray());
                } catch (Exception e) {
                    System.err.println("更新失败: " + e.getMessage());
                    return false;
                }

            } else {
                // 构建插入SQL语句
                Set<String> tagKeys = tags.keySet();
                Set<String> fieldKeys = fields.keySet();
                sql = InsertSqlUtil.buildInsertSql(tableName, tagKeys, fieldKeys);

                try {
                    jdbcTemplate.update(connection -> {
                        PreparedStatement pstmt = connection.prepareStatement(sql);
                        int index = 1;
                        for (String tagValue : tags.values()) {
                            pstmt.setString(index++, tagValue);
                        }
                        for (Object fieldValue : fields.values()) {
                            pstmt.setObject(index++, fieldValue);
                        }
                        return pstmt;
                    });
                } catch (Exception e) {
                    System.err.println("插入失败: " + e.getMessage());
                    return false;
                }
            }
        }

        return true;
    }


    /**
     * 根据设备ID查询remoteId
     * @param sensorId
     * @return
     */
    @Override
    public String queryRemoteIdBYSensorId(String sensorId) {
        IotSensor one = iotSensorMapper.selectOne(new QueryWrapper<IotSensor>().eq("sensor_id", sensorId));
        return one.getDeviceId();
    }

    @Override
    public Boolean batchSaveToInfluxDB(String measurement, List<Map<String, Object>> batchData) {
        if (batchData == null || batchData.isEmpty()) {
            throw new IllegalArgumentException("批量数据不能为空");
        }

        for (Map<String, Object> data : batchData) {
            Map<String, String> tags = (Map<String, String>) data.get("tags");
            Map<String, Object> fields = (Map<String, Object>) data.get("fields");

            if (tags == null || fields == null) {
                throw new IllegalArgumentException("每条数据必须包含 tags 和 fields");
            }

            // 获取时间戳（如果存在）
            Object reportTimeObj = fields.get("report_time");
            Long timestamp = null;

            if (reportTimeObj instanceof Long) {
                timestamp = (Long) reportTimeObj;
            } else if (reportTimeObj instanceof Date) {
                timestamp = ((Date) reportTimeObj).getTime();
            } else if (reportTimeObj != null) {
                try {
                    timestamp = Long.parseLong(reportTimeObj.toString());
                } catch (NumberFormatException e) {
                    System.err.println("无法解析时间戳字段: " + reportTimeObj);
                }
            }

            // 调用 influxDB 插入方法
            if (timestamp != null) {
                saveToInfluxDB(timestamp, measurement, tags, fields);
            } else {
                saveToInfluxDB(measurement, tags, fields);
            }
        }

        return true;
    }

    @Override
    public String geSensorIdByRemoteIdANDFuncCode(String deviceId, String funcCode) {
        List<IotSensor> sensors = iotSensorMapper.selectByDeviceIdAndParamOne(deviceId,funcCode);
//        List<IotSensor> sensors = iotSensorMapper.selectList(new QueryWrapper<IotSensor>()
//            .eq("device_id", deviceId)
//            .apply("FIND_IN_SET({0}, param_one)", funcCode));
        if (ObjectUtil.isEmpty(sensors)){
            return null;
        }
        String sensorId = sensors.get(0).getSensorId();
        return sensorId;
    }

    @Override
    public void saveSensorMsg(IotSensorMsg build) {
        List<IotSensorMsg> list = iotSensorMsgMapper.selectOneByRemoteIdAndReportTime(build.getRemoteId(),build.getReportTime());
//        List<IotSensorMsg> list = iotSensorMsgMapper.selectList(new QueryWrapper<IotSensorMsg>()
//            .eq("remote_id", build.getRemoteId())
//            .eq("report_time", build.getReportTime())
//        );
        if (ObjectUtil.isEmpty(list)){
            int insert = iotSensorMsgMapper.insert(build);
        }

    }

    @Override
    public Map<String, IotDataWaterPressureInfo> getAllPressureInfo() {
        List<IotDataWaterPressureInfo> allPressureInfo = iotSensorMsgMapper.getAllPressureInfo();
        Map<String, IotDataWaterPressureInfo> pressureInfoMap = allPressureInfo.stream()
                .collect(Collectors.toMap(
                        IotDataWaterPressureInfo::getDeviceId, // 假设 IotDataWaterPressureInfo 中有 getDeviceId() 方法
                        info -> info
                ));
        return pressureInfoMap;
    }


    private String BuildQueryParameter(Map<String, Object> params){
        String from = (String) params.get("from");
        String to = (String) params.get("to");
        String remoteId = (String) params.getOrDefault("remoteId", null);
        String time = (String) params.getOrDefault("time", "1d");
        String limit = (String) params.getOrDefault("limit", null);
        String measurement = (String) params.getOrDefault("measurement", "");
        Map<String, List<String>> measurementDictMap = getMeasurementDictMap(measurement);
        List<String> fields = measurementDictMap.get("field");
        String firstFieldsClause = buildFirstFieldsClause(fields);
        String SQL = "SELECT " + firstFieldsClause + " FROM \"" + measurement + "\"";
        SQL = SQL.concat(" WHERE "
//
        );
        if( !ObjectUtils.isEmpty(from) && !ObjectUtils.isEmpty(to)) {
            SQL = SQL.concat(  "time >= " + from + "ms and time <= " + to + "ms AND ");
        } else {

            if( !ObjectUtils.isEmpty(limit)) {
                SQL = SQL.concat(  " time <= " + System.currentTimeMillis() + "ms AND ");
            }
        }
        if (!ObjectUtils.isEmpty(remoteId)) {
            SQL = SQL.concat("  (\"remoteId\" = \'" +  remoteId + "\') ");
        }
        SQL = SQL.concat(" GROUP BY time(" + time + ")  ")
            .concat(" ORDER BY time DESC");

        if( !ObjectUtils.isEmpty(limit)) {
            SQL = SQL.concat(" LIMIT " + limit);
        }

        return SQL;
    }

    private String buildFirstFieldsClause(List<String> fields) {
        return fields.stream()
            .map(field -> "last(\"" + field + "\") as " + field + " ")
            .collect(Collectors.joining(", "));
    }

    private Map<String, List<String>> getMeasurementDictMap(String measurement) {
        Map<String, List<String>> measurementDictMap = new HashMap<>();
        List<IotMeasurementDict> list = iotMeasurementDictMapper.selectListByMeasurement(measurement);
        measurementDictMap.putAll(list.stream()
            .collect(Collectors.groupingBy(IotMeasurementDict::getType,
                Collectors.mapping(IotMeasurementDict::getName, Collectors.toList()))));
        return measurementDictMap;
    }



}
